home *** CD-ROM | disk | FTP | other *** search
- ; This is AKALAH.LSP modified to use an array for the playing field rather
- ; than a list. The major result is a modest increase in speed because of
- ; greatly reduced garbage collections
-
- ; To play against the computer:
- ; (meplay #pits-per-side #pebbles-per-pit #search-depth #computer-plays-first)
- ;
- ; To have the computer play against itself:
- ; (play #pits-per-side #pebbles-per-pit #search-depth)
-
-
- ; The playing arena:
- ; 13 12 11 10 9 8 7
- ; 0 1 2 3 4 5 6
-
-
- (defun makefield (length contents)
- (let ((result (make-array length)))
- (dotimes (i length) (setf (aref result i) contents))
- result))
-
- (setq *maxvalue* 1000)
- (setq *minvalue* (- *maxvalue*))
-
- (defun copy (array) (generic array)) ; not the generic solution!
-
- (defun prinb (x) (dotimes (i x) (princ #\space)))
-
- (defun search (startpos depth whoseturn)
- (if (zerop depth)
- (list startpos (evaluate startpos whoseturn))
- (let (bestval nextval bestpos succlist)
- (setq succlist (successorsfn startpos whoseturn))
- (when (> depth 1) (setq succlist (reorder succlist whoseturn)))
- (setq
- beta *maxvalue*
- bestval *minvalue*
- bestpos (car succlist))
- (dolist (this succlist)
- (when (wincheck this whoseturn)
- (return-from search (list this *maxvalue*)))
- (setq nextval (- (alphabeta this
- (- beta)
- (- bestval)
- (1- depth)
- (not whoseturn))))
- (when (> nextval bestval)
- (setq bestval nextval)
- (setq bestpos this)))
- (list bestpos bestval)))) ; return value
-
- (defun alphabeta (position alpha beta depth whoseturn)
- (if (zerop depth)
- (evaluate position whoseturn)
- (let (bestval nextval succlist)
- (setq succlist (successorsfn position whoseturn))
- (when (> depth 1) (setq succlist (reorder succlist whoseturn)))
- (setq bestval alpha)
- (dolist (this succlist)
- (when (wincheck this whoseturn)
- (return-from alphabeta *maxvalue*))
- (setq nextval (- (alphabeta this
- (- beta)
- (- bestval)
- (1- depth)
- (not whoseturn))))
- (when (> nextval bestval) (setq bestval nextval))
- (when (<= beta bestval) (return-from alphabeta bestval)))
- bestval)))
-
- (defun successorsfn (position whoseturn
- &aux
- (picuphole (1- (if whoseturn *firstb* *firsta*)))
- succlist
- succ
- stones
- disthole
- lasthole)
- (dotimes (dummy *enda*)
- (when (not (zerop (aref position (setq picuphole (1+ picuphole)))))
- (setq succ (copy position))
- (setq stones (aref succ picuphole)) ; stones in this pit
- (empty succ picuphole)
- (setq disthole picuphole)
- (dotimes (dummy2 stones) ; drop in successive holes except
- ; opponents kalah hole
- (setq disthole (nextdistholefn disthole whoseturn))
- (dropin succ disthole 1))
- (setq lasthole disthole)
- (cond ((allownzerok succ whoseturn) ; all played out
- (opptakesallfn succ whoseturn))
- ((eq lasthole (kalaholefn whoseturn)) ; last in kalah
- (setq succ (successorsfn succ whoseturn)))
- ((and (eq (aref succ lasthole) 1) ; last into own empty
- (> (aref succ (opposholefn lasthole)) 0)
- (ownsidep lasthole whoseturn))
- (dropin succ
- (kalaholefn whoseturn)
- (1+ (aref succ (opposholefn lasthole))))
- (empty succ lasthole)
- (empty succ (opposholefn lasthole))
- (when (allownzerok succ whoseturn)
- (opptakesallfn succ whoseturn))))
- (setq succlist (nconc (preparelisfn succ) succlist))))
- (if (null succlist)
- (progn (setq succ (copy position))
- (opptakesallfn succ whoseturn)
- (list succ))
- succlist))
-
- (defun dropin (position hole number)
- (setf (aref position hole) (+ number (aref position hole))))
-
- (defun nextdistholefn (disthole whoseturn)
- (cond ((and whoseturn (eql disthole *lasta*)) *firstb*) ; skip own pile
- ((and (not whoseturn) (eql disthole *lastb*)) *firsta*)
- ((< disthole *endb*) (1+ disthole))
- (t *firsta*)))
-
- (defun empty (position hole) ; empty out the given hole
- (setf (aref position hole) 0))
-
- (defun kalaholefn (whoseturn) ; the scoring hole for the given player
- (if whoseturn *endb* *enda*))
-
- (defun opposholefn (hole) ; calculate the opposing hole
- (- *lastb* hole))
-
- (defun ownsidep (hole whoseturn)
- (if whoseturn (> hole *enda*) (< hole *firstb*)))
-
- (defun preparelisfn (x)
- (if (arrayp x)
- (list x)
- (unimbedfn x)))
-
- (defun reorder (poslist whoseturn)
- (sortdown poslist (statvalsfn poslist whoseturn)))
-
-
- (defun sortdown (poslist statvalvec)
- (if (null (cdr poslist))
- poslist
- (let ((maxindex (indexfn statvalvec)))
- (cons (nth maxindex poslist)
- (sortdown (deletel maxindex poslist)
- (deletel maxindex statvalvec))))))
-
- (defun deletel (index list) ; delete the index'th value in list
- (if (zerop index)
- (cdr list)
- (prog2
- (rplacd (nthcdr (1- index) list) (nthcdr (1+ index) list))
- list)))
-
- (defun indexfn (x &aux result) ; find position of maximum value
- (do ((list x (cdr list))
- (n 0 (1+ n))
- (val *minvalue* (cond ((> (car list) val)
- (setq result n)
- (car list))
- (t val))))
- ((null list) result)))
-
- (defun statvalsfn (poslist whoseturn)
- (if (null poslist)
- 'nil
- (cons (evaluate (car poslist) whoseturn)
- (statvalsfn (cdr poslist) whoseturn))))
-
- (defun wincheck (position whoseturn)
- (> (aref position (kalaholefn whoseturn)) *halfall*))
-
- (defun evaluate (position whoseturn) ; assign the value to the position
- ; could obviously use work
- (let ((ownkala (aref position (kalaholefn whoseturn)))
- (oppkala (aref position (kalaholefn (not whoseturn)))))
- (cond ((> ownkala *halfall*) *maxvalue*)
- ((> oppkala *halfall*) *minvalue*)
- (t (- ownkala oppkala)))))
-
- (defun printpos (position)
- (terpri)
- (prin1 (aref position *enda*))
- (prinb (if (> 10 (aref position *enda*)) 3 2))
- (dotimes (n *enda*)
- (let ((val (aref position (- *enda* n 1))))
- (prin1 val)
- (prinb (if (> 10 val) 2 1))))
- (terpri)
- (prinb 4)
- (dotimes (n *enda*)
- (let ((val (aref position (+ *firstb* n))))
- (prin1 val)
- (prinb (if (> 10 val) 2 1))))
- (prinb 2)
- (prin1 (aref position *endb*))
- (terpri)
- (terpri))
-
- ; sum the players pieces yet to play
- (defun countown (position whoseturn)
- (let ((start (if whoseturn *firstb* *firsta*))
- (sum 0))
- (dotimes (n *enda*)
- (setf sum (+ sum (aref position (+ n start)))))
- sum))
-
- ; check if player is out of pieces (then opponent will take remainder)
- (defun allownzerok (position whoseturn)
- (zerop (countown position whoseturn)))
-
- (defun opptakesallfn (position whoseturn)
- (dropin position
- (kalaholefn (not whoseturn))
- (countown position (not whoseturn)))
- (do ((count *enda* (1- count))
- (hole (if whoseturn *firstb* *firsta*) (1+ hole)))
- ((zerop count))
- (empty position hole)))
-
- (defun nextmove (depth whoseturn)
- (terpri)
- (setq *board* (search (car *board*) depth whoseturn))
- (printpos (car *board*))
- (print (cdr *board*))
- (terpri))
-
- ; (defun unimbedfn (poslist)
- ; (cond ((null poslist) 'nil)
- ; ((atom (caar poslist))
- ; (cons (car poslist) (unimbedfn (cdr poslist))))
- ; (t (append (unimbedfn (car poslist))
- ; (unimbedfn (cdr poslist))))))
-
- (defun unimbedfn (poslist)
- (do ((list poslist (cdr list))
- (result nil (if (arrayp (car list))
- (cons (car list) result)
- (append (unimbedfn (car list)) result))))
- ((null list) result)))
-
- (defun initialize (holes pebbles &aux temp) ; initialize the playing area
- (setq *enda* holes)
- (setq *endb* (+ holes holes 1))
- (setq *firsta* 0)
- (setq *lasta* (1- *enda* ))
- (setq *firstb* (1+ *enda*))
- (setq *lastb* (1- *endb*))
- (setq *halfall* (* holes pebbles))
- (setq temp (makefield (+ (* 2 holes) 2) pebbles))
- (setf (aref temp *enda*) 0)
- (setf (aref temp *endb*) 0)
- (setq *board* (list temp 0)))
-
- (defun play (holes pebbles depth) ; play the game
- (initialize holes pebbles)
- (do ((whoseturn nil (not whoseturn)))
- ((or (eql (cadr *board*) *maxvalue*)
- (eql (cadr *board*) *minvalue*)))
- (nextmove depth whoseturn)))
-
- (defun meplay (holes pebbles depth computer-first)
- (prog (picuphole)
- (initialize holes pebbles)
- (when computer-first (setq succ (copy (car *board*)))
- (go y))
- n (setq succ (copy (car *board*)))
- (printpos succ)
- (if (> (aref succ *enda*) *halfall*) (return t)) ; win for side a
- (if (> (aref succ *endb*) *halfall*) (return nil)) ; win for side b
- x (princ "Hole? ") (setq picuphole (read))
- (if (or (not (numberp picuphole))
- (> picuphole *firstb*)
- (> 1 picuphole)
- (zerop (setq stones (aref succ (setq picuphole (1- picuphole))))))
- (go x))
- (empty succ picuphole)
- (setq disthole picuphole)
- (dotimes (dummy stones)
- (dropin succ (setq disthole (nextdistholefn disthole nil)) 1))
- (setq lasthole disthole)
- (cond ((allownzerok succ nil)
- (opptakesallfn succ nil)
- (setq *board* (list succ 0))
- (go n))
- ((eql lasthole *enda*)
- (setq *board* (list succ 0))
- (go n))
- ((and (eql (nth lasthole succ) 1)
- (> (aref succ (opposholefn lasthole)) 0)
- (> *enda* lasthole))
- (dropin succ *enda* (1+ (aref succ(opposholefn lasthole))))
- (empty succ lasthole)
- (empty succ (opposholefn lasthole))
- (when (allownzerok succ nil)
- (opptakesallfn succ nil)
- (setq *board* (list succ 0))
- (go n))))
- (printpos succ)
- y (setq *board* (search succ depth t))
- (go n)))
-
-